// Image Resource
// (c) jimon game studio

#ifndef JEH_JEIMAGERESOURCE
#define JEH_JEIMAGERESOURCE

#include "IResourceManager.h"
#include "IImageLoader.h"
#include "ITexture.h"
#include "jeStl.h"
#include "IRender.h"
#include "jeSharedResource.h"

#include "ILogManager.h"

namespace je
{
	namespace media
	{
		//! Image Resource
		class jeImageResource:public je::media::IResource
		{
		public:
			typedef jeSharedResourceManagerUniversal jeSharedTextureResourceManager;
		protected:
			video::IImage * Image;
			jeVector2di FrameSize;
			video::TextureFormat Format;
			s32 TextureFlags;

			jeSharedTextureResourceManager * SharedManager;
		public:
			//! Constructor
			jeImageResource(const jeStringc & ResourceName)
				:IResource(ResourceName),Image(NULL)
			{
				JENEW(SharedManager,jeSharedTextureResourceManager)
			}

			//! Constructor
			jeImageResource(const jeStringc & ResourceName,video::IImage * NewImage,const jeVector2di & NewFrameSize,s32 NewTextureFlags)
				:IResource(ResourceName,false),Image(NewImage),FrameSize(NewFrameSize),TextureFlags(NewTextureFlags)
			{
				if(Image)
					Image->Grab();
				JENEW(SharedManager,jeSharedTextureResourceManager)
			}

			//! Destructor
			~jeImageResource()
			{
				JEDELETE(SharedManager)

				if(Image)
					Image->Drop();
			}

			//! Get Shared Manager
			jeSharedTextureResourceManager * GetSharedManager()
			{
				return SharedManager;
			}

			//! Get Image
			video::IImage * GetImage()
			{
				return Image;
			}

			//! Get Frame Size
			const jeVector2di & GetFrameSize()
			{
				return FrameSize;
			}

			//! Get Texture Format
			video::TextureFormat GetTextureFormat()
			{
				return Format;
			}

			//! Get Texture Flags
			s32 GetTextureFlags()
			{
				return TextureFlags;
			}

			//! Load Parameters
			void LoadParameters()
			{
				if(!ParametersLoad)
				{
					core::IDataBase_Query * Query = GetResourceManager()->GetDataBase()->Query(jeStringc("SELECT * FROM ImageResources WHERE Name = '")+CurrentResourceName+jeStringc("'"));
					FrameSize.X = Query->GetFields32("FrameX");
					FrameSize.Y = Query->GetFields32("FrameY");
					Format = (video::TextureFormat)Query->GetFields32("Format");
					TextureFlags = Query->GetFields32("Flags");
					Query->Drop();
				}

				IResource::LoadParameters();
			}

			//! Load Resource
			void Load()
			{
				#ifdef JE_RESOURCES_IMAGE_USEBLOBBUFFER
				core::IDataBase_Query * Query = GetResourceManager()->GetDataBase()->Query(jeStringc("SELECT ROWID,* FROM ImageResources WHERE Name = '")+CurrentResourceName+jeStringc("'"));
				if(!ParametersLoad)
				{
					FrameSize.X = Query->GetFields32("FrameX");
					FrameSize.Y = Query->GetFields32("FrameY");
					Format = (video::TextureFormat)Query->GetFields32("Format");
					TextureFlags = Query->GetFields32("Flags");
				}
				s32 RowId = Query->GetFields32(0,0);
				Query->Drop();
				core::IBuffer * Buffer = GetResourceManager()->GetDataBase()->GetBlobBuffer("ImageResources","Data",RowId);
				if(Buffer)
				{
					Image = video::GetImageLoader()->LoadImage(Buffer);
					Buffer->Drop();
				}
				else
					Image = video::CreateImage(FrameSize,video::IImage::ICF_R8G8B8A8);
				#else
				core::IDataBase_Query * Query = GetResourceManager()->GetDataBase()->Query(jeStringc("SELECT * FROM ImageResources WHERE Name = '")+CurrentResourceName+jeStringc("'"));
				if(!ParametersLoad)
				{
					FrameSize.X = Query->GetFields32("FrameX");
					FrameSize.Y = Query->GetFields32("FrameY");
					Format = (video::TextureFormat)Query->GetFields32("Format");
					TextureFlags = Query->GetFields32("Flags");
				}
				core::jeMemoryBuffer * Buffer = Query->GetFieldBuffer("Data");
				if(Buffer)
				{
					Image = video::GetImageLoader()->LoadImage(Buffer);
					Buffer->Drop();
				}
				else
					Image = video::CreateImage(FrameSize,video::IImage::ICF_R8G8B8A8);
				Query->Drop();
				#endif
			}

			//! UnLoad Resource
			void UnLoad()
			{
				Image->Drop();
				Image = NULL;
			}

			//! Get Type Name
			virtual jeStringc GetTypeName()
			{
				return jeStringc("ImageResource");
			}
		};

		//! Image Resource Factory
		class jeImageResourceFactory:public je::media::IResourceFactory
		{
		protected:
			typedef jeMap<jeStringc,jeImageResource*> ImageMapType;
			ImageMapType ImageMap;
		public:

			//! Constructor
			jeImageResourceFactory()
			{
			}

			//! Destructor
			~jeImageResourceFactory()
			{
				ClearResources();
			}

			//! Add Resources
			void AddResources(IResource * Resource)
			{
				ImageMap.set(Resource->GetName(),static_cast<jeImageResource*>(Resource));
				Resource->Grab();
			}

			//! Load Resources
			void LoadResources()
			{
				ClearResources();

				core::IDataBase_Query * Query = GetResourceManager()->GetDataBase()->Query("SELECT * FROM ImageResources");
				while(!Query->Eof())
				{
					jeStringc ResourceName = Query->GetFieldjeStringc("Name");
					jeImageResource * ImageResource = NULL;
					JENEW(ImageResource,jeImageResource(ResourceName))
					ImageMap.set(ResourceName,ImageResource);
					Query->NextRow();
				}
				Query->Drop();
			}

			//! Clear Resources
			void ClearResources()
			{
				for(ImageMapType::Iterator Iter = ImageMap.getIterator();!Iter.atEnd();Iter++)
					Iter->getValue()->Drop();
				ImageMap.clear();
			}

			//! Return Resource
			IResource * GetResource(const jeStringc & ResourceName)
			{
				ImageMapType::Node * Node = ImageMap.find(ResourceName);
				if(Node)
					return Node->getValue();
				else
					return NULL;
			}

			//! Return Resource Type
			jeStringc GetResourceType()
			{
				return jeStringc("ImageResource");
			}

			//! Garbage Collector
			void GarbageCollector()
			{
				for(ImageMapType::Iterator Iter = ImageMap.getIterator();!Iter.atEnd();Iter++)
					if(Iter->getValue()->IsNeedToUnload())
						Iter->getValue()->GarbageUnload();
			}
		};

		//! Shared Texture
		class jeSharedTexture:public media::ISharedResource
		{
		protected:
			s32 FramesCount;
			video::ITexture ** Frames;
			jeStringc ImageResourceName;
			jeVector2di FrameSize;
		public:
			//! Constructor
			jeSharedTexture(jeImageResource * ImageResource,video::IRender * CurrentRender)
			{
				ImageResource->AddUsage();
				ImageResourceName = ImageResource->GetName();
				FrameSize = ImageResource->GetFrameSize();
				video::IImage * Image = ImageResource->GetImage();
				if((FrameSize.X != 0) && (FrameSize.Y != 0))
				{
					FramesCount = Image->GetSize().X / FrameSize.X;
					JENEW_A(Frames,video::ITexture*,FramesCount)

					for(s32 i=0;i<FramesCount;i++)
					{
						video::IImage * Temp = Image->Copy(jeVector2di(FrameSize.X * i,0),FrameSize);
						Frames[i] = CurrentRender->CreateTexture(Temp,ImageResource->GetTextureFormat(),ImageResource->GetTextureFlags());
						Temp->Drop();
					}
				}
				else
				{
					FramesCount = 1;
					JENEW_A(Frames,video::ITexture*,FramesCount)
					Frames[0] = CurrentRender->CreateTexture(Image,ImageResource->GetTextureFormat(),ImageResource->GetTextureFlags());
					FrameSize = Frames[0]->GetSize();
				}
				ImageResource->RemoveUsage();
			}

			//! Destructor
			~jeSharedTexture()
			{
				for(s32 i=0;i<FramesCount;i++)
					Frames[i]->Drop();
				JEDELETE_A(Frames)
			}

			//! Get Count
			s32 GetCount()
			{
				return FramesCount;
			}

			//! Get Resource Name
			const jeStringc & GetResourceName()
			{
				return ImageResourceName;
			}

			//! Get Frame Size
			const jeVector2di & GetFrameSize()
			{
				return FrameSize;
			}

			//! Get Texture Array
			video::ITexture ** Get()
			{
				return Frames;
			}

			//! Get First Texture
			video::ITexture * GetFirst()
			{
				return Frames[0];
			}
		};
	}
}

#define JE_IMAGERESOURCE( __Name ) JE_RESOURCEBASE_GET(__Name,ImageResource)

#define JE_IMAGERESOURCE_GRAB( __Var, __Res, __Key, __Render ) JE_RESOURCEBASE_SHARED_GRAB(__Var,__Res,__Key,__Render,Texture)
#define JE_IMAGERESOURCE_DROP( __Var, __Key, __Render) JE_RESOURCEBASE_SHARED_DROP(__Var,__Key,ImageResource)

#define JE_IMAGERESOURCE_SHARED_GRAB( __Var, __Res, __Render ) JE_IMAGERESOURCE_GRAB(__Var,__Res,__Render->GetContext(),__Render)
#define JE_IMAGERESOURCE_SHARED_DROP( __Var, __Render) JE_IMAGERESOURCE_DROP(__Var,__Render->GetContext(),__Render)

#endif
